function fakeParseJSON(str) {
    let i = 0;
  
    const value = parseValue();
    // expectEndOfInput();
    return value;
  
    /**
     * 解析对象
     */
    function parseObject() {
      if (str[i] === "{") {
        i++;
        skipWhitespace();
  
        const result = {};
  
        let initial = true;
        // if it is not '}',
        // we take the path of string -> whitespace -> ':' -> value -> ...
        while (i < str.length && str[i] !== "}") {
          if (!initial) {
            eatComma();
            skipWhitespace();
          }
          const key = parseString();
          if (key === undefined) {
            expectObjectKey();
          }
          skipWhitespace();
          eatColon();
          const value = parseValue();
          result[key] = value;
          initial = false;
        }
        expectNotEndOfInput("}");
        // move to the next character of '}'
        i++;
  
        return result;
      }
    }
  
    /**
     * 解析数组
     */
    function parseArray() {
      if (str[i] === "[") {
        i++;
        skipWhitespace();
  
        const result = [];
        let initial = true;
        while (i < str.length && str[i] !== "]") {
          if (!initial) {
            eatComma();
          }
          const value = parseValue();
          result.push(value);
          initial = false;
        }
        expectNotEndOfInput("]");
        // move to the next character of ']'
        i++;
        return result;
      }
    }
  
    /**
     * 辅助函数， 便于递归
     */
    function parseValue() {
      skipWhitespace();
      const value =
        parseString() ??
        parseNumber() ??
        parseObject() ??
        parseArray() ??
        parseKeyword("true", true) ??
        parseKeyword("false", false) ??
        parseKeyword("null", null);
      skipWhitespace();
      return value;
    }
  
    /**
     * 解析关键词
     * @param {*} name 
     * @param {*} value 
     */
    function parseKeyword(name, value) {
      if (str.slice(i, i + name.length) === name) {
        i += name.length;
        return value;
      }
    }
  
    /**
     * 跳过空格
     */
    function skipWhitespace() {
      while (
        str[i] === " " ||
        str[i] === "\n" ||
        str[i] === "\t" ||
        str[i] === "\r"
      ) {
        i++;
      }
    }
  
    /**
     * 解析字符串
     */
    function parseString() {
      if (str[i] === '"') {
        i++;
        let result = "";
        while (i < str.length && str[i] !== '"') {
          if (str[i] === "\\") {
            const char = str[i + 1];
            if (
              char === '"' ||
              char === "\\" ||
              char === "/" ||
              char === "b" ||
              char === "f" ||
              char === "n" ||
              char === "r" ||
              char === "t"
            ) {
              result += char;
              i++;
            } else if (char === "u") {
              if (
                isHexadecimal(str[i + 2]) &&
                isHexadecimal(str[i + 3]) &&
                isHexadecimal(str[i + 4]) &&
                isHexadecimal(str[i + 5])
              ) {
                result += String.fromCharCode(
                  parseInt(str.slice(i + 2, i + 6), 16)
                );
                i += 5;
              } else {
                i += 2;
                expectEscapeUnicode(result);
              }
            } else {
              expectEscapeCharacter(result);
            }
          } else {
            result += str[i];
          }
          i++;
        }
        expectNotEndOfInput('"');
        i++;
        return result;
      }
    }
  
    /**
     * 判断十六进制
     * @param {*} char 
     */
    function isHexadecimal(char) {
      return (
        (char >= "0" && char <= "9") ||
        (char.toLowerCase() >= "a" && char.toLowerCase() <= "f")
      );
    }
  
    /**
     * 解析数字
     */
    function parseNumber() {
      let start = i;
      if (str[i] === "-") {
        i++;
        expectDigit(str.slice(start, i));
      }
      if (str[i] === "0") {
        i++;
      } else if (str[i] >= "1" && str[i] <= "9") {
        i++;
        while (str[i] >= "0" && str[i] <= "9") {
          i++;
        }
      }
  
      if (str[i] === ".") {
        i++;
        expectDigit(str.slice(start, i));
        while (str[i] >= "0" && str[i] <= "9") {
          i++;
        }
      }
      if (str[i] === "e" || str[i] === "E") {
        i++;
        if (str[i] === "-" || str[i] === "+") {
          i++;
        }
        expectDigit(str.slice(start, i));
        while (str[i] >= "0" && str[i] <= "9") {
          i++;
        }
      }
      if (i > start) {
        return Number(str.slice(start, i));
      }
    }
    
    /**
     * 处理逗号
     */
    function eatComma() {
      expectCharacter(",");
      i++;
    }
  
    /**
     * 处理分号
     */
    function eatColon() {
      expectCharacter(":");
      i++;
    }

    function expectCharacter(expected) {
        if (str[i] !== expected) {
          printCodeSnippet(`Expecting a \`${expected}\` here`);
          throw new Error("JSON_ERROR_0004 Unexpected token");
        }
      }
  
    function printCodeSnippet(message) {
      const from = Math.max(0, i - 10);
      const trimmed = from > 0;
      const padding = (trimmed ? 4 : 0) + (i - from);
      const snippet = [
        (trimmed ? "... " : "") + str.slice(from, i + 1),
        " ".repeat(padding) + "^",
        " ".repeat(padding) + message
      ].join("\n");
      console.log(snippet);
    }
  }
  
  // console.log("Try uncommenting the fail cases and see their error message");
  // console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
  
  // Fail cases:
  printFailCase("-");
  printFailCase("-1.");
  printFailCase("1e");
  printFailCase("-1e-2.2");
  printFailCase("{");
  printFailCase("{}{");
  printFailCase('{"a"');
  printFailCase('{"a": "b",');
  printFailCase('{"a":"b""c"');
  printFailCase('{"a":"foo\\}');
  printFailCase('{"a":"foo\\u"}');
  printFailCase("[");
  printFailCase("[][");
  printFailCase("[[]");
  printFailCase('["]');
  
  function printFailCase(json) {
    try {
      console.log(`fakeParseJSON('${json}')`);
      fakeParseJSON(json);
    } catch (error) {
      console.error(error);
    }
  }
  